package com.itheima.service.impl;

import cn.idev.excel.ExcelWriter;
import cn.idev.excel.FastExcel;
import cn.idev.excel.write.metadata.WriteSheet;
import com.itheima.common.vo.*;
import com.itheima.mapper.MemberMapper;
import com.itheima.mapper.OrderMapper;
import com.itheima.mapper.SetMealMapper;
import com.itheima.service.ReportService;
import lombok.RequiredArgsConstructor;
// import org.apache.xmlbeans.ResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @className ReportServiceImpl
 */
@Service
@RequiredArgsConstructor
public class ReportServiceImpl implements ReportService {

    private static final DateTimeFormatter REPORT_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy.MM.dd");
    private final MemberMapper memberMapper;
    private final SetMealMapper setMealMapper;
    private final OrderMapper orderMapper;
    private final ResourceLoader resourceLoader;

    /**
     * 会员统计报表（柱状图）
     * @return ReportMemberVo
     **/
    public ReportMemberVo getMemberReport() {

        // 0、获取过去12个月的每月最后一天日期
        List<LocalDate> monthEndDates = IntStream.rangeClosed(0, 11)
                .mapToObj(i -> LocalDate.now().minusMonths(11 - i).with(TemporalAdjusters.lastDayOfMonth()))
                .collect(Collectors.toList());

        // 1、组装x轴数据
        List<String> months = monthEndDates.stream()
                // 格式化前端指定日期
                .map(REPORT_DATE_FORMATTER::format)
                .collect(Collectors.toList());

        // 2、组装y轴数据
        List<Integer> memberCounts = monthEndDates.stream()
                .map(endDate -> {
                    // 获取当月第一天
                    LocalDate startDate = endDate.withDayOfMonth(1);
                    // 查询该月新增会员数量
                    Integer count = memberMapper.countNewMembersBetweenDates(startDate, endDate);
                    return count != null ? count : 0;
                }).collect(Collectors.toList());

        //3、组装返回值
        return ReportMemberVo.builder()
                .months(months)
                .memberCount(memberCounts)
                .build();
    }

    /**
     * 套餐占比统计报表（饼状图）
     * @return ReportSetMealVo
     **/
    public ReportSetMealVo getSetMealReport() {
        //获取所有套餐名称
        List<String> setMealNames = setMealMapper.selectSetMealNames();
        List<ReportSetMealCountVo> setMealCounts = setMealNames.stream()
                .map(setMealName -> {
                    // 获取套餐名称对应的套餐数量
                    Integer count = setMealMapper.countSetMealByName(setMealName);
                    // 组装套餐数量
                    return ReportSetMealCountVo.builder()
                            .name(setMealName)
                            .value(count)
                            .build();
                }).collect(Collectors.toList());
        //组装返回值
        return ReportSetMealVo.builder()
                .setmealNames(setMealNames)
                .setmealCount(setMealCounts)
                .build();
    }

    /**
     * 运营数据统计报表
     * @return ReportBusinessVo
     **/
    public ReportBusinessVo getBusinessReportData() {

        // 初始化日期
        LocalDate today = LocalDate.now();
        LocalDate startOfWeek = today.with(DayOfWeek.MONDAY);// 本周第一天
        LocalDate startOfMonth = today.withDayOfMonth(1);// 本月第一天

        // 查询热门套餐数据，取前四个
        List<ReportBusinessHotSetMealVo> hotSetmeal = setMealMapper.selectSetMealsOrderCount();
        // 写法1：计算套餐的总预约数
        // 写法2：Integer total = setMealMapper.selectSetMealCountTotal(); //sql层查询总数
        int totalOrders = hotSetmeal.stream()
                .mapToInt(ReportBusinessHotSetMealVo::getSetmeal_count)
                .sum();

        // 写法1：计算每个套餐的占比（每个套餐的预约数/套餐的总预约数）
        // 写法2：ROUND(COUNT(o.setmeal_id) * 1.0 / (SELECT COUNT(*) FROM t_order), 4) AS proportion
        hotSetmeal.forEach(vo -> vo.setProportion(
                BigDecimal.valueOf(vo.getSetmeal_count())
                        .divide(BigDecimal.valueOf(totalOrders), 4, RoundingMode.HALF_UP)));

        return ReportBusinessVo.builder()
                // 1、会员数据统计
                .todayNewMember(memberMapper.countNewMembersBetweenDates(today, today))
                .totalMember(memberMapper.countAllMembers())
                .thisWeekNewMember(memberMapper.countNewMembersBetweenDates(startOfWeek, today))
                .thisMonthNewMember(memberMapper.countNewMembersBetweenDates(startOfMonth, today))
                // 2、预约数据统计
                .todayOrderNumber(orderMapper.countOrders(today, today))
                .thisWeekOrderNumber(orderMapper.countOrders(startOfWeek, today))
                .thisMonthOrderNumber(orderMapper.countOrders(startOfMonth, today))
                // 3、到访数据统计
                .todayVisitsNumber(orderMapper.countVisits(today, today))
                .thisWeekVisitsNumber(orderMapper.countVisits(startOfWeek, today))
                .thisMonthVisitsNumber(orderMapper.countVisits(startOfMonth, today))
                // 4、热门套餐数据统计
                .hotSetmeal(hotSetmeal)
                .reportDate(today)
                .build();
    }

    /**
     * 导出Excel运营数据统计报表
     * @return void
     **/
    public String exportBusinessReportByExcel(ReportBusinessVo reportBusinessVo) {
        String fileName = "运营报告_" + LocalDate.now() + "_" + UUID.randomUUID() + ".xlsx";
        // 输出文件路径
        Path outputPath = Paths.get("E:/", fileName);
        try {
            // 确保目录存在
            Files.createDirectories(outputPath.getParent());
            // 使用try-with-resources处理资源
            try (OutputStream outputStream = Files.newOutputStream(outputPath);
                 InputStream templateStream = resourceLoader.getResource("classpath:templates/report_template.xlsx").getInputStream()) {
                // 创建ExcelWriter
                try (ExcelWriter excelWriter = FastExcel.write(outputStream).withTemplate(templateStream).build()) {
                    WriteSheet writeSheet = FastExcel.writerSheet(0).build();
                    // 填充基础数据
                    excelWriter.fill(reportBusinessVo, writeSheet);
                }
            }
            // 返回文件下载路径
            return "/download/" + fileName;
        } catch (IOException e) {
            throw new RuntimeException("导出Excel失败", e);
        }
    }

}
